home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FM Towns: Free Software Collection 10
/
FM Towns Free Software Collection 10.iso
/
ms_dos
/
tool
/
mercury
/
install.c
< prev
next >
Wrap
Text File
|
1995-02-05
|
17KB
|
770 lines
/*
MercuryInstaller for MS-DOS
インストール&QQQファイル処理ルーチン
*/
#include<ctype.h>
#include<direct.h>
#include<dos.h>
#include<farstr.h>
#include<fcntl.h>
#include<io.h>
#include<jstring.h>
#include<setjmp.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/stat.h>
#include"mercury.h"
/*****************************************************************************/
/* グローバル変数 */
/*****************************************************************************/
static char Sourcedir[128] = ""; /* コピー元のディレクトリ */
static int Qqqlevel = 0; /* QQQファイルの再帰レベル */
/*****************************************************************************/
/* 下請け処理 */
/*****************************************************************************/
/*-----------------------------コピー元パスの作成----------------------------*/
/* 指定されたパスが相対パスによるものであれば、それにドライブ名・パス名をつけ*/
/* 加える */
/*---------------------------------------------------------------------------*/
static void mksourcepath(char *d,char *s)
{
if (s[1]==':') /* ドライブ名から指定 */
strcpy(d,s);
else if (s[0]=='\\') /* 標準ドライブのルートから指定 */
sprintf(d,"%c:%s",Drive,s);
else /* 標準ディレクトリから指定 */
sprintf(d,"%c:%s\\%s",Drive,Sourcedir,s);
if (Sourcedir[0]=='\0')
{
char *p;
if (s[1]==':')
strcpy(Sourcedir,s+2);
else if (s[0]=='\\')
strcpy(Sourcedir,s);
p = jstrrchr(Sourcedir,'\\');
if (p!=NULL)
*p = '\0';
}
}
/*---------------ディレクトリが存在するかどうかチェック----------------------*/
static int is_directory_exist(char *path)
{
char buf[128];
if (getcwd(buf,sizeof(buf))==NULL)
return 0;
if (chdir(path)!=0)
return 0;
chdir(buf);
return 1;
}
/*------------------------パス名の直後の位置を探す---------------------------*/
static char *afterpath(char *s)
{
char *p = jstrrchr(s,'\\');
if (p!=NULL)
return p+1;
else if (s[1]==':')
return s+2;
else
return s;
}
/*----------------------パス名の最後に'\\'をつけ加える-----------------------*/
/* 関数の値としては'\\'をつけ加えた後の位置を返す。 */
/*---------------------------------------------------------------------------*/
static char *addbackslash(char *s)
{
char *p = strchr(s,'\0');
if (p!=s && p[-1]!='\\' && p[-1]!=':')
{
p[0] = '\\';
p[1] = '\0';
return p+1;
}
else
return p;
}
/*****************************************************************************/
/* QQQファイル */
/*****************************************************************************/
/*-----------------各コマンド処理ルーチンのプロトタイプ宣言------------------*/
/* 本当は私、static関数のプロトタイプ宣言は嫌いなんですが...(^_^;)こうしない */
/* と、ifコマンドの処理で間接再帰を使うのでうまく書けないのです(;_;)。 */
/*---------------------------------------------------------------------------*/
static int cmd_dummy(char *);
static int cmd_chdir(char *);
static int cmd_copy(char *);
static int cmd_exit(char *);
static int cmd_if(char *);
static int cmd_inst(char *);
static int cmd_look(char *);
static int cmd_mkdir(char *);
static int cmd_pause(char *);
static int cmd_rename(char *);
static int cmd_xcopy(char *);
/*-------------------------------型と変数------------------------------------*/
static struct COMMANDS
{
char *str;
int (*func)(char *);
} Commands[] =
{
{"chdir" ,cmd_chdir },
{"copy" ,cmd_copy },
{"else" ,cmd_dummy },
{"endif" ,cmd_dummy },
{"exit" ,cmd_exit },
{"if" ,cmd_if },
{"inst" ,cmd_inst },
{"look" ,cmd_look },
{"mkdir" ,cmd_mkdir },
{"pause" ,cmd_pause },
{"play" ,cmd_dummy },
{"rename",cmd_rename},
{"xcopy" ,cmd_xcopy },
};
typedef enum
{
CMD_CHDIR,CMD_COPY,CMD_ELSE,CMD_ENDIF,CMD_EXIT,CMD_IF,CMD_INST,
CMD_LOOK,CMD_MKDIR,CMD_PAUSE,CMD_PLAY,CMD_RENAME,CMD_XCOPY,
CMD_EOF,
} COMMANDID;
jmp_buf Jmp_buf;
/*----------------------QQQファイルのアクセスルーチン------------------------*/
/* qqq_fgetsは、*argに内部のstaticバッファへのポインタを返す。従って、次に呼 */
/* ばれるまでその内容は有効。 */
/*---------------------------------------------------------------------------*/
static FILE *Qqqfile[FOPEN_MAX+1]; /* 1..FOPEN_MAX */
static int qqq_fopen(char *filename)
{
char buf[128];
FILE *fp;
mksourcepath(buf,filename);
fp = fopen(buf,"r");
if (fp==NULL)
{
putmessage("%sがオープンできません",buf);
return 0;
}
Qqqfile[++Qqqlevel] = fp;
return 1;
}
static void qqq_fclose(void)
{
fclose(Qqqfile[Qqqlevel--]);
}
static COMMANDID qqq_fgets(char **arg)
{
static char buf[512];
char *p,*q;
int i;
rep:
if (Qqqlevel==0)
return CMD_EOF;
if (fgets(buf,sizeof(buf),Qqqfile[Qqqlevel])==NULL)
{
qqq_fclose();
goto rep;
}
if ((p=strchr(buf,'\n'))!=NULL)
*p = '\0';
p = buf;
while (isspace(*p))
p++;
if (*p=='#' || *p=='\0')
goto rep;
q = p;
while (isalpha(*p))
p++;
*p = '\0';
do
p++;
while (isspace(*p));
*arg = p;
for (i=0 ; i<MEMBERSOF(Commands) ; i++)
{
if (stricmp(q,Commands[i].str)==0)
return (COMMANDID)i;
}
putmessage("QQQファイルに不正な命令があります:%s",q);
longjmp(Jmp_buf,-1);
}
static void qqq_release(void)
{
while (Qqqlevel)
qqq_fclose();
}
/*-----------------QQQファイル解釈ルーチンのメインルーチン-------------------*/
static int qqqinterpreter(char *filename)
{
char *p;
int a;
COMMANDID id;
if (!qqq_fopen(filename))
return 0;
a = setjmp(Jmp_buf);
if (a!=0)
{
qqq_release();
if (a<0) return 0;
else return 1;
}
while ((id=qqq_fgets(&p))!=CMD_EOF)
{
if (!Commands[id].func(p))
{
qqq_release();
return 0;
}
}
qqq_release();
return 1;
}
/*****************************************************************************/
/* QQQファイルの各コマンドの処理 */
/*****************************************************************************/
/*-----------------------------ダミーコマンド--------------------------------*/
static int cmd_dummy(char *s)
{
return 1;
}
/*------------------------------chdirコマンド--------------------------------*/
static int cmd_chdir(char *s)
{
if (chdir(s)==0)
return 1;
putmessage("ディレクトリ%sがありません");
return 0;
}
/*-------------------------------copyコマンド--------------------------------*/
static int cmd_copy(char *s)
{
char *p = s;
static int copy(int f,char *s,char *d);
while (!isspace(*p))
p++;
if (*p!='\0')
{
*p++ = '\0';
while (isspace(*p))
p++;
}
return copy(0,s,p);
}
/*------------------------------exitコマンド---------------------------------*/
static int cmd_exit(char *s)
{
longjmp(Jmp_buf,1);
}
/*-------------------------------ifコマンド----------------------------------*/
static int cmd_if(char *mes)
{
COMMANDID id;
char *p;
int c;
c = window_select(mes,"Y:はい","N:いいえ",NULL);
if (c=='Y' || c=='y')
{
while ((id=qqq_fgets(&p))!=CMD_ELSE &&
id!=CMD_ENDIF && id!=CMD_EOF)
{
if (!Commands[id].func(p))
return 0;
}
if (id==CMD_ELSE)
{
while ((id=qqq_fgets(&p))!=CMD_ENDIF && id!=CMD_EOF)
;
}
}
else
{
while ((id=qqq_fgets(&p))!=CMD_ELSE &&
id!=CMD_ENDIF && id!=CMD_EOF)
;
if (id==CMD_ELSE)
{
while ((id=qqq_fgets(&p))!=CMD_ENDIF && id!=CMD_EOF)
{
if (!Commands[id].func(p))
return 0;
}
}
}
return 1;
}
/*-------------------------------instコマンド--------------------------------*/
static int cmd_inst(char *s)
{
return qqq_fopen(s);
}
/*-------------------------------lookコマンド--------------------------------*/
/* Helperとの互換性のため一応ダミーを用意しておく */
/*---------------------------------------------------------------------------*/
static int cmd_look(char *s)
{
openwindow(2,64);
window_putstr(0,"LOOK:\n%s",s);
ds_getch();
closewindow();
return 1;
}
/*------------------------------mkdirコマンド--------------------------------*/
static int cmd_mkdir(char *s)
{
if (mkdir(s)==0)
return 1;
putmessage("ディレクトリ%sが作れません");
return 0;
}
/*-------------------------------pauseコマンド-------------------------------*/
static int cmd_pause(char *s)
{
openwindow(1,strlen(s)+1);
window_putstr(0,"%s",s);
ds_getch();
closewindow();
return 1;
}
/*------------------------------renameコマンド-------------------------------*/
static int cmd_rename(char *s)
{
char *p = s;
while (!isspace(*p))
p++;
if (*p=='\0')
{
putmessage("RENAMEコマンドの書式が不正です");
return 0;
}
*p = '\0';
while (isspace(*p))
p++;
if (rename(s,p)==0)
return 1;
putmessage("RENAMEできませんでした");
return 0;
}
/*------------------------------xcopyコマンド--------------------------------*/
static int cmd_xcopy(char *s)
{
char *p = s;
static int copy(int f,char *s,char *d);
while (!isspace(*p))
p++;
if (*p!='\0')
{
*p++ = '\0';
while (isspace(*p))
p++;
}
return copy(1,s,p);
}
/*****************************************************************************/
/* ファイルのコピー */
/*****************************************************************************/
/*------------------------単一ファイルのコピー-------------------------------*/
/* 次の要件を満たすとき、srcをQQQファイルとみなしてqqqinterpreter()を呼び出 */
/* す。 */
/* ○srcが示すのがQQQファイルである */
/* ○このcopy_onefile()がQQQファイルの(X)COPY命令から呼ばれたものでない */
/* すなわち、QQQlevel==0 */
/*---------------------------------------------------------------------------*/
/* なぜか高水準入出力を使うと極端にパフォーマンスが落ちるので、あえて低水準 */
/* 入出力を使用している */
/*---------------------------------------------------------------------------*/
static int copy_onefile(char *src,char *dst)
{
int fdi=-1,fdo=-1;
long size,size2;
int n;
char buf[4096];
if (Qqqlevel==0)
{
char *p = strchr(src,'\0');
if (p>src+4 && stricmp(p-4,".qqq")==0)
return qqqinterpreter(src);
}
openwindow(4,64);
diet_setmode(0);
fdi=open(src,O_RDONLY);
if (fdi==-1)
{
window_putstr(0,"%sがオープンできません",src);
ds_getch();
goto error;
}
fdo=open(dst,O_WRONLY|O_TRUNC|O_CREAT,S_IREAD|S_IWRITE);
if (fdo==-1)
{
window_putstr(0,"%sがオープンできません",dst);
ds_getch();
goto error;
}
size = filelength(fdi);
size2 = 0;
window_putstr(0,"%s\n",dst);
window_putstr(3,"[ESC]/[F10]で中止します");
{
unsigned date,time;
_dos_getftime(fdi,&date,&time);
_dos_setftime(fdo,date,time);
}
while ((n=read(fdi,buf,sizeof(buf)))>0) /* エラー処理は少々手抜き */
{
if (write(fdo,buf,n)==-1)
goto error;
size2 += n;
window_putstr(2,"%ld/%ld",size2,size);
if (ds_kbhit())
{
int c = ds_getch();
if (c==FKEY_ESC || c==FKEY_F10)
{
closewindow();
openwindow(1,14);
window_putstr(0,"中止しました.");
goto error;
}
}
}
close(fdi);
close(fdo);
closewindow();
diet_setmode(1);
return 1;
error:
if (fdi!=NULL) close(fdi);
if (fdo!=NULL) close(fdo);
closewindow();
diet_setmode(1);
return 0;
}
/*--------------------ファイルを検索して線形リストに格納---------------------*/
struct DIRCHAIN
{
char name[13];
char attr;
unsigned time;
unsigned date;
unsigned long size;
struct DIRCHAIN *next;
};
struct DIRCHAIN *ds_opndir(char *path, char attr)
{
char *chp;
struct find_t fib;
struct DIRCHAIN *dirtop;
struct DIRCHAIN *dir;
static char buf[128];
strncpy(buf, path, sizeof(buf)-1);
chp = strchr(buf,'\0') -1;
if (*chp==':' || *chp=='\\')
strncat(buf, "*.*", sizeof(buf) - 1);
if (_dos_findfirst(buf, (unsigned)attr, &fib))
return NULL;
if ((dir = malloc(sizeof(struct DIRCHAIN))) == NULL)
return NULL;
dirtop = dir;
strcpy(dir->name, fib.name);
dir->attr = fib.attrib;
dir->time = fib.wr_time;
dir->date = fib.wr_date;
dir->size = fib.size;
dir->next = NULL;
while (_dos_findnext(&fib) == 0)
{
if ((dir->next = malloc(sizeof(struct DIRCHAIN))) == NULL)
return NULL;
dir = dir->next;
strcpy(dir->name, fib.name);
dir->attr = fib.attrib;
dir->time = fib.wr_time;
dir->date = fib.wr_date;
dir->size = fib.size;
dir->next = NULL;
}
return dirtop;
}
/*-----------------単一ファイル→単一ファイルのコピーか?---------------------*/
static int is_single_to_single(char *src,char *dst)
{
char *p;
if (jstrchr(src,'*')!=NULL || jstrchr(src,'?')!=NULL)
return 0;
p = strchr(dst,'\0');
if (p==dst || p[-1]=='\\' || p[-1]==':')
return 0;
if (is_directory_exist(dst))
return 0;
if (access(src,4)==0)
return 1;
else
return 0;
}
/*----------------指定されたパスの親ディレクトリがなければ作る---------------*/
static int mkparentdir(char *path)
{
char *p;
int n = 0;
while ((p=jstrrchr(path,'\\'))!=NULL)
{
*p = '\0';
n++;
if (chdir(path)==0)
break;
}
for ( ; n ; *strchr(path,'\0')='\\',n--)
{
char buf[128];
int c;
if (chdir(path)==0)
continue;
if (path[0]=='\0' || (path[1]==':' && path[2]=='\0'))
continue;
strcpy(buf,path);
strcat(buf,"\nディレクトリが存在しません 作りますか?");
c = window_select(buf,"Y:はい","N:いいえ",NULL);
if (c=='N' || c=='n')
goto error;
if (mkdir(path)!=0)
{
putmessage("ディレクトリ%sが作れません",path);
goto error;
}
}
return 1;
error:
while (n--)
*strchr(path,'\0') = '\\';
return 0;
}
/*-------------------------COPY/XCOPYの下請け再帰関数------------------------*/
/* srcとdstの内容は破壊されるので注意 */
/*---------------------------------------------------------------------------*/
recursive static int xcopy_sub(int isxcopy,char *src,char *dst)
{
char *s = afterpath(src);
char *d = afterpath(dst);
struct DIRCHAIN *dir = ds_opndir(src,_A_NORMAL|_A_SUBDIR);
while (dir!=NULL)
{
struct DIRCHAIN *temp;
if (dir->name[0]=='.')
goto next;
strcpy(s,dir->name);
strcpy(d,dir->name);
if (dir->attr & _A_SUBDIR)
{
if (!isxcopy)
{
char buf[128];
int c;
sprintf(buf,"%sディレクトリもコピーしますか?",
dir->name);
c=window_select(buf,"Y:はい","N:いいえ",NULL);
if (c=='N' || c=='n')
goto next;
}
if (!is_directory_exist(dst) && mkdir(dst))
{
putmessage("ディレクトリ%sが作れません",dst);
goto error;
}
strcat(s,"\\*.*");
strcat(d,"\\");
if (!xcopy_sub(isxcopy,src,dst))
goto error;
}
else
{
if (!copy_onefile(src,dst))
goto error;
}
next:
temp = dir;
free(dir);
dir = temp->next;
}
return 1;
error:
while (dir!=NULL)
{
struct DIRCHAIN *temp = dir;
free(dir);
dir = temp->next;
}
return 0;
}
/*---------------------------コピーのメインルーチン--------------------------*/
static int copy(int isxcopy,char *src,char *dst)
{
char src2[128];
char dst2[128];
mksourcepath(src2,src);
strcpy(dst2,dst);
if (is_single_to_single(src2,dst2))
{
if (!mkparentdir(dst2))
return 0;
else
return copy_onefile(src2,dst2);
}
addbackslash(dst2);
if (!mkparentdir(dst2))
return 0;
return xcopy_sub(isxcopy,src2,dst2);
}
/*****************************************************************************/
/* インストーラのメインルーチン */
/*****************************************************************************/
extern void installer(struct DATA far *data)
{
static char target[128] = "";
char buf[128];
struct COPYDATA_T far *p;
char *s;
strcpy(buf,target);
if (!window_strinput("インストール先のディレクトリを指定してください",buf,64))
return;
if (data->dir!=NULL)
far_strcpy(Sourcedir,data->dir);
else
Sourcedir[0] = '\0'; /* qqqinterpreter()で設定する? */
strcpy(target,buf);
s = addbackslash(buf) - 1;
if (!mkparentdir(buf))
return;
if (s!=buf && s[-1]!=':')
*s = '\0';
chdir(buf);
if (buf[1]==':')
bdos(0x0e,toupper(buf[0])-'A',0);
if (data->copy==NULL)
{
copy(0,"*.*","");
return;
}
for (p=data->copy ; p!=NULL ; p=p->next)
{
far_strcpy(buf,p->string);
if (!copy(p->isxcopy,buf,""))
return;
}
}
/*-----------------------------End of install.c------------------------------*/